<template>
  <div class="speech-training-container">
    <!-- 头部区域 -->
    <header class="training-header">
      <div class="header-content">
        <h1><i class="fas fa-microphone-alt"></i> 中文发音训练系统</h1>
        <p class="subtitle">提升您的中文发音准确性，获得专业评测反馈</p>
      </div>
    </header>
    <div class="main-content">
      <!-- 训练区域 -->
      <div class="training-section">
        <h2 class="section-title">
          <i class="fas fa-running"></i> 训练内容
        </h2>
        <!-- 初始状态 - 开始训练按钮 -->
        <div v-if="!trainingStarted" class="start-container">
          <button @click="startTraining" class="start-btn">
            <i class="fas fa-play"></i> 开始发音训练
          </button>
          <p class="start-hint">点击开始获取AI生成的中文训练内容</p>
        </div>
        <!-- 训练内容展示 -->
        <div v-if="trainingStarted" class="training-items">
          <!-- 每个训练项 -->
          <div v-for="(item, index) in trainingItems" :key="index" class="training-item">
            <div class="item-header">
              <div class="item-number">{{ index + 1 }}</div>
              <div v-if="item.recording" class="recording-indicator">
                <div class="pulse"></div>
                <span>录音中...</span>
                <span class="timer">{{ formatTime(item.recordingTime) }}</span>
              </div>
              <div v-if="item.evaluating" class="evaluating-indicator">
                <i class="fas fa-spinner fa-spin"></i>
                <span>评测中...</span>
              </div>
              <div v-if="item.result" class="result-indicator">
                <i class="fas fa-check-circle"></i>
                <span>评测完成: {{ getPercentage(item.result.total_score) }}</span>
              </div>
            </div>
            <div class="item-content">
              {{ item.text }}
              <div v-if="item.pinyin" class="pinyin-hint">{{ item.pinyin }}</div>
            </div>
            <div class="recording-controls">
              <button 
                @click="toggleRecording(index)"
                class="recording-btn"
                :class="{ recording: item.recording }"
                :disabled="isSubmitting || item.evaluating"
              >
                <i :class="item.recording ? 'fas fa-stop' : 'fas fa-microphone'"></i>
                {{ item.recording ? '结束录音' : '开始录音' }}
              </button>
              <div v-if="item.audioUrl" class="audio-preview">
                <audio controls :src="item.audioUrl"></audio>
              </div>
            </div>
            
            <!-- 句子评测结果 -->
            <div v-if="item.result" class="sentence-result">
              <div class="result-summary">
                <div class="result-item">
                  <span>总分:</span>
                  <span class="score-value">{{ getPercentage(item.result.total_score) }}</span>
                </div>
                <div class="result-item">
                  <span>流利度:</span>
                  <span class="score-value">{{ getPercentage(item.result.fluency_score) }}</span>
                </div>
                <div class="result-item">
                  <span>准确度:</span>
                  <span class="score-value">{{ getPercentage(item.result.phone_score) }}</span>
                </div>
                <div class="result-item">
                  <span>语调:</span>
                  <span class="score-value">{{ getPercentage(item.result.tone_score) }}</span>
                </div>
              </div>
            </div>
          </div>
          
          <!-- 提交按钮 -->
          <div v-if="allRecorded" class="submit-section">
            <button 
              @click="submitEvaluations" 
              class="submit-btn"
              :disabled="isSubmitting || hasEvaluating"
            >
              <i class="fas fa-cloud-upload-alt"></i> 
              {{ isSubmitting ? '评测中...' : '提交评测' }}
            </button>
          </div>
        </div>
      </div>
      
      <!-- 评测结果区域 -->
      <div class="results-section">
        <h2 class="section-title">
          <i class="fas fa-chart-bar"></i> 评测结果
        </h2>
        <!-- 初始提示 -->
        <div v-if="!hasResults" class="empty-results">
          <i class="fas fa-comment-dots"></i>
          <p>完成训练并提交后，您将在此看到详细的评测结果</p>
        </div>
        <!-- 评测结果展示 -->
        <div v-if="hasResults" class="results-container">
          <!-- 总体评分 -->
          <div class="overall-score">
            <div class="score-card">
              <div class="score-label">总体评分</div>
              <div class="score-value">{{ overallScore }}</div>
              <div class="score-percentage">{{ overallScore }}%</div>
              <div class="score-progress">
                <div class="progress-bar" :style="{ width: overallScore + '%' }"></div>
              </div>
            </div>
          </div>
          <!-- 详细评分 -->
          <div class="detailed-scores">
            <div class="score-item">
              <div class="score-info">
                <div class="score-label">声调准确度</div>
                <div class="score-value">{{ detailedScores.tones }}</div>
              </div>
              <el-progress 
                :percentage="detailedScores.tones" 
                :stroke-width="12"
                color="#4CAF50"
              />
            </div>
            <div class="score-item">
              <div class="score-info">
                <div class="score-label">声母/韵母</div>
                <div class="score-value">{{ detailedScores.initialsFinals }}</div>
              </div>
              <el-progress 
                :percentage="detailedScores.initialsFinals" 
                :stroke-width="12"
                color="#2196F3"
              />
            </div>
            <div class="score-item">
              <div class="score-info">
                <div class="score-label">流畅度</div>
                <div class="score-value">{{ detailedScores.fluency }}</div>
              </div>
              <el-progress 
                :percentage="detailedScores.fluency" 
                :stroke-width="12"
                color="#FFC107"
              />
            </div>
          </div>
          
          <!-- 详细分析 -->
          <div class="detailed-analysis">
            <h3><i class="fas fa-search"></i> 详细分析</h3>
            <div class="analysis-item" v-for="(item, index) in analysisDetails" :key="index">
              <div class="analysis-content">
                <i :class="item.icon" :style="{ color: item.color }"></i>
                <p>{{ item.text }}</p>
              </div>
            </div>
          </div>
          
          <!-- 重新训练按钮 -->
          <div class="retry-section">
            <button @click="resetTraining" class="retry-btn">
              <i class="fas fa-redo"></i> 重新训练
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { ref, computed } from 'vue'
import axios from 'axios'

export default {
  setup() {
    // 状态管理
    const trainingStarted = ref(false)
    const trainingItems = ref([])
    const isSubmitting = ref(false)
    const hasResults = ref(false)
    const overallScore = ref(0)
    const detailedScores = ref({
      tones: 0,
      initialsFinals: 0,
      fluency: 0
    })
    const analysisDetails = ref([])
    const audioContext = ref(null)
    const audioProcessors = ref([])
    const audioChunks = ref([])

    // 计算属性
    const allRecorded = computed(() => {
      return trainingItems.value.length > 0 && 
             trainingItems.value.every(item => item.audioBlob || item.recording)
    })
    
    const hasEvaluating = computed(() => {
      return trainingItems.value.some(item => item.evaluating)
    })

    // 方法
    const startTraining = async () => {
      trainingStarted.value = true
      try {
        // 构建符合要求的请求格式 - 修改为面试场景提示词
        const requestData = {
          question: "请直接生成3个纯粹的面试场景中文句子，从面试者（求职者）视角出发，不要包含任何额外描述或说明，不要有序号，每个句子包含不同声调组合。只要求三个相关句子，禁止添加其他成分包括序号。",
          userId: 123,
          deepThinking: true,
          networkSearch: false,
          messages: [
            {
              role: 'system',
              content: '你是一个中文发音训练助手，专门为面试准备提供支持。请直接返回纯粹的面试场景中文句子，从面试者（求职者）视角出发，不要包含任何描述、说明、标题或编号。只要求三个相关句子，禁止添加其他成分包括序号。'
            },
            {
              role: 'user',
              content: "请直接生成3个纯粹的面试场景中文句子，从面试者（求职者）视角出发，不要包含任何额外描述或说明，不要有序号，每个句子包含不同声调组合。只要求三个相关句子，禁止添加其他成分包括序号。"
            }
          ]
        }

        // 调用chat接口获取训练内容
        const response = await axios.post('http://localhost:8080/chat', requestData, {
          headers: { 'Content-Type': 'application/json' }
        })

        // 解析响应数据
        const trainingData = parseTrainingResponse(response.data)
        
        // 初始化训练项
        trainingItems.value = trainingData.map(item => ({
          text: item.text,
          pinyin: item.pinyin,
          recording: false,
          recordingTime: 0,
          audioBlob: null,
          audioUrl: null,
          result: null,
          evaluating: false,
          recorder: null,
          timer: null
        }))

        // 初始化录音相关数组
        audioProcessors.value = Array(trainingData.length).fill(null)
        audioChunks.value = Array(trainingData.length).fill([])
      } catch (error) {
        console.error('获取训练内容失败:', error)
        alert('获取训练内容失败，请重试')
        // 使用默认训练内容作为回退（面试者视角）
        trainingItems.value = [
          { text: "我对这个职位有浓厚的兴趣，相信自己能胜任", pinyin: "Wǒ duì zhège zhíwèi yǒu nóng hòu de xìngqù, xiāngxìn zìjǐ néng shèngrèn" },
          { text: "我在上一家公司负责产品设计与团队管理", pinyin: "Wǒ zài shàng yī jiā gōngsī fùzé chǎnpǐn shèjì yǔ tuánduì guǎnlǐ" },
          { text: "我的优势是沟通能力和解决问题的经验", pinyin: "Wǒ de yōushì shì gōutōng nénglì hé jiějué wèntí de jīngyàn" }
        ].map(item => ({
          text: item.text,
          pinyin: item.pinyin,
          recording: false,
          recordingTime: 0,
          audioBlob: null,
          audioUrl: null,
          result: null,
          evaluating: false,
          recorder: null,
          timer: null
        }))
      }
    }

    const parseTrainingResponse = (data) => {
      try {
        // 默认回退内容（面试者视角）
        const defaultData = [
          { text: "我对这个职位有浓厚的兴趣，相信自己能胜任", pinyin: "Wǒ duì zhège zhíwèi yǒu nóng hòu de xìngqù, xiāngxìn zìjǐ néng shèngrèn" },
          { text: "我在上一家公司负责产品设计与团队管理", pinyin: "Wǒ zài shàng yī jiā gōngsī fùzé chǎnpǐn shèjì yǔ tuánduì guǎnlǐ" },
          { text: "我的优势是沟通能力和解决问题的经验", pinyin: "Wǒ de yōushì shì gōutōng nénglì hé jiějué wèntí de jīngyàn" }
        ]
        
        // 情况1：已经是数组，直接返回
        if (Array.isArray(data)) {
          // 处理每个句子，去除序号
          const processedData = data.map(item => {
            let text = item.text || item;
            // 去除序号前缀
            text = removeNumberPrefix(text);
            return {
              text,
              // pinyin: item.pinyin || "自动生成拼音"
            }
          });
          return processedData.slice(0, 3);
        }
        
        // 情况2：对象类型，尝试提取内容
        if (typeof data === 'object' && data !== null) {
          // 尝试可能的字段
          if (Array.isArray(data.sentences)) {
            return data.sentences.slice(0, 3).map(s => ({
              text: removeNumberPrefix(s.text || s),
              // pinyin: s.pinyin || "自动生成拼音"
            }))
          }
          if (data.content && typeof data.content === 'string') {
            return extractPureSentences(data.content)
          }
        }
        
        // 情况3：字符串类型，尝试解析为JSON
        if (typeof data === 'string') {
          try {
            const parsed = JSON.parse(data)
            return parseTrainingResponse(parsed)
          } catch (e) {
            // 作为纯文本处理
            return extractPureSentences(data)
          }
        }
        
        return defaultData
      } catch (error) {
        console.error('解析训练内容失败:', error)
        return [
          { text: "我对这个职位有浓厚的兴趣，相信自己能胜任", pinyin: "Wǒ duì zhège zhíwèi yǒu nóng hòu de xìngqù, xiāngxìn zìjǐ néng shèngrèn" },
          { text: "我在上一家公司负责产品设计与团队管理", pinyin: "Wǒ zài shàng yī jiā gōngsī fùzé chǎnpǐn shèjì yǔ tuánduì guǎnlǐ" },
          { text: "我的优势是沟通能力和解决问题的经验", pinyin: "Wǒ de yōushì shì gōutōng nénglì hé jiějué wèntí de jīngyàn" }
        ]
      }
    }
    
    // 去除句子前的序号
    const removeNumberPrefix = (text) => {
      // 匹配并去除开头的数字+标点（如 "1."、"2、"、"3) " 等）
      return text.replace(/^\d+[\.、\)]\s*/, '').trim();
    }
    
    // 从文本中提取纯句子内容
    const extractPureSentences = (text) => {
      // 1. 尝试按句号分割
      let sentences = text.split(/[。！？]/).filter(s => s.trim().length > 0)
      
      // 2. 如果句子数量不足，尝试按换行符分割
      if (sentences.length < 3) {
        sentences = text.split('\n').filter(s => s.trim().length > 0)
      }
      
      // 3. 过滤掉包含说明性文字的句子
      const filtered = sentences.filter(s => {
        const lower = s.toLowerCase()
        return !lower.includes("以下是") && 
               !lower.includes("面试场景") && 
               !lower.includes("普通话训练") &&
               !lower.includes("示例") &&
               !lower.includes("句子") &&
               !lower.includes("：")
      })
      
      // 4. 处理每个句子，去除序号
      const processed = filtered.map(s => removeNumberPrefix(s)).filter(s => s.trim().length > 0)
      
      // 5. 取前3个有效的句子
      const result = processed.slice(0, 3).map(text => ({
        text: text.trim(),
        // pinyin: "自动生成拼音"
      }))
      
      // 6. 如果结果不足3个，补充默认句子
      while (result.length < 3) {
        result.push({
          text: defaultInterviewSentences[result.length],
          // pinyin: "自动生成拼音"
        })
      }
      
      return result
    }
    
    // 默认面试句子库（面试者视角）
    const defaultInterviewSentences = [
      "我对这个职位有浓厚的兴趣，相信自己能胜任",
      "我在上一家公司负责产品设计与团队管理",
      "我的优势是沟通能力和解决问题的经验",
      "我期待能为贵公司创造价值",
      "我有五年的行业经验，熟悉市场运作",
      "我的职业目标是成为行业专家",
      "我善于团队协作，能够高效完成工作",
      "我对新技术充满热情，学习能力强",
      "我具备良好的分析和解决问题的能力",
      "我期待在贵公司长期发展"
    ]

    const toggleRecording = async (index) => {
      const item = trainingItems.value[index]
      if (item.recording) {
        // 停止录音
        stopRecording(index)
      } else {
        // 开始录音
        startRecording(index)
      }
    }

    const startRecording = async (index) => {
      try {
        // 设置音频约束，确保符合讯飞要求：16kHz, 16bit, 单声道
        const constraints = {
          audio: {
            sampleRate: 16000,
            channelCount: 1,
            sampleSize: 16,
            echoCancellation: false,
            noiseSuppression: false,
            autoGainControl: false
          }
        }
        
        const stream = await navigator.mediaDevices.getUserMedia(constraints)
        const item = trainingItems.value[index]
        
        // 创建音频上下文
        audioContext.value = new (window.AudioContext || window.webkitAudioContext)({
          sampleRate: 16000
        })
        
        // 创建音频源
        const source = audioContext.value.createMediaStreamSource(stream)
        
        // 创建处理器
        const processor = audioContext.value.createScriptProcessor(4096, 1, 1)
        audioProcessors.value[index] = processor
        
        // 初始化音频数据存储
        audioChunks.value[index] = []
        
        processor.onaudioprocess = (event) => {
          const inputData = event.inputBuffer.getChannelData(0)
          const output = new Int16Array(inputData.length)
          
          // 将Float32转换为Int16 PCM
          for (let i = 0; i < inputData.length; i++) {
            const s = Math.max(-1, Math.min(1, inputData[i]))
            output[i] = s < 0 ? s * 0x8000 : s * 0x7FFF
          }
          
          audioChunks.value[index].push(output)
        }
        
        // 连接处理链
        source.connect(processor)
        processor.connect(audioContext.value.destination)
        
        // 更新状态
        trainingItems.value[index].recording = true
        trainingItems.value[index].timer = setInterval(() => {
          trainingItems.value[index].recordingTime++
        }, 1000)
        
      } catch (error) {
        console.error('录音失败:', error)
        alert('无法访问麦克风，请检查权限设置')
      }
    }

    const stopRecording = (index) => {
      const processor = audioProcessors.value[index]
      if (processor) {
        processor.disconnect()
      }
      
      if (audioContext.value) {
        audioContext.value.close()
        audioContext.value = null
      }
      
      const item = trainingItems.value[index]
      clearInterval(item.timer)
      item.recording = false
      
      // 合并音频数据
      const chunks = audioChunks.value[index]
      if (chunks && chunks.length > 0) {
        const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0)
        const mergedData = new Int16Array(totalLength)
        let offset = 0
        
        for (const chunk of chunks) {
          mergedData.set(chunk, offset)
          offset += chunk.length
        }
        
        // 创建PCM Blob
        const audioBlob = new Blob([mergedData.buffer], { type: 'audio/pcm' })
        // 创建用于播放的WAV格式
        const wavBlob = pcmToWav(mergedData)
        const audioUrl = URL.createObjectURL(wavBlob)
        
        // 更新训练项
        trainingItems.value[index].audioBlob = audioBlob
        trainingItems.value[index].audioUrl = audioUrl
      }
      
      audioChunks.value[index] = []
    }
    
    // PCM转WAV格式用于播放
    const pcmToWav = (pcmData) => {
      const WAV_HEADER_SIZE = 44;
      const buffer = new ArrayBuffer(WAV_HEADER_SIZE + pcmData.length * 2);
      const view = new DataView(buffer);
      
      // 写入WAV头部
      writeString(view, 0, 'RIFF');
      view.setUint32(4, 36 + pcmData.length * 2, true);
      writeString(view, 8, 'WAVE');
      writeString(view, 12, 'fmt ');
      view.setUint32(16, 16, true);
      view.setUint16(20, 1, true); // 格式类别：PCM
      view.setUint16(22, 1, true); // 声道数
      view.setUint32(24, 16000, true); // 采样率
      view.setUint32(28, 16000 * 2, true); // 数据传输率
      view.setUint16(32, 2, true); // 块对齐
      view.setUint16(34, 16, true); // 采样位数
      writeString(view, 36, 'data');
      view.setUint32(40, pcmData.length * 2, true);
      
      // 写入PCM数据
      const dataView = new Int16Array(buffer, WAV_HEADER_SIZE);
      for (let i = 0; i < pcmData.length; i++) {
        dataView[i] = pcmData[i];
      }
      
      return new Blob([view], { type: 'audio/wav' });
    }
    
    const writeString = (view, offset, string) => {
      for (let i = 0; i < string.length; i++) {
        view.setUint8(offset + i, string.charCodeAt(i));
      }
    }

    const formatTime = (seconds) => {
      const mins = Math.floor(seconds / 60)
      const secs = seconds % 60
      return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
    }

    // 评测单个句子的函数 - 简化版，只解析主要分数
    const evaluateSpeech = async (text, audioBlob, index) => {
      const formData = new FormData()
      formData.append('audio', audioBlob, `recording_${index}.pcm`)
      formData.append('text', text)

      try {
        // 设置当前句子为评测状态
        trainingItems.value[index].evaluating = true
        
        const response = await fetch('http://localhost:8080/evaluate', {
          method: 'POST',
          body: formData
        })

        if (!response.ok) {
          const errorData = await response.text()
          throw new Error(errorData || '评测失败')
        }

        const responseText = await response.text()
        const parser = new DOMParser()
        const xmlDoc = parser.parseFromString(responseText, "text/xml")
        
        // 提取主要评分信息
        const readSentence = xmlDoc.querySelector('read_sentence[accuracy_score]')
        if (!readSentence) {
          throw new Error('无效的评测结果格式')
        }
        
        return {
          content: readSentence.getAttribute('content') || text,
          total_score: readSentence.getAttribute('total_score') || '0',
          fluency_score: readSentence.getAttribute('fluency_score') || '0',
          phone_score: readSentence.getAttribute('phone_score') || '0',
          tone_score: readSentence.getAttribute('tone_score') || '0'
        }
        
      } catch (error) {
        console.error('评测出错:', error)
        // 返回默认结构防止页面崩溃
        return {
          content: text,
          total_score: '0',
          fluency_score: '0',
          phone_score: '0',
          tone_score: '0'
        }
      } finally {
        trainingItems.value[index].evaluating = false
      }
    }

    const submitEvaluations = async () => {
      if (!allRecorded.value || isSubmitting.value) return
      isSubmitting.value = true
      
      try {
        // 重置之前的评测结果
        trainingItems.value.forEach(item => {
          item.result = null
        })
        
        // 逐个评测每个句子
        for (let i = 0; i < trainingItems.value.length; i++) {
          const item = trainingItems.value[i]
          try {
            // 延迟发送请求，避免同时发送多个请求
            await new Promise(resolve => setTimeout(resolve, 500))
            
            const result = await evaluateSpeech(item.text, item.audioBlob, i)
            // 将评测结果保存到对应的训练项中
            trainingItems.value[i].result = result
          } catch (error) {
            console.error(`第${i+1}个句子评测失败:`, error)
            // 可以在这里添加错误处理，比如显示错误信息
          }
        }
        
        // 计算总体评分
        calculateOverallScores()
        hasResults.value = true
        
      } catch (error) {
        console.error('提交评测失败:', error)
        alert('评测提交失败，请重试')
      } finally {
        isSubmitting.value = false
      }
    }
    
    const calculateOverallScores = () => {
      // 只计算有结果的句子
      const validItems = trainingItems.value.filter(item => item.result)
      
      if (validItems.length === 0) return
      
      // 计算平均分
      const totalScores = validItems.map(item => parseFloat(item.result.total_score))
      const fluencyScores = validItems.map(item => parseFloat(item.result.fluency_score))
      const phoneScores = validItems.map(item => parseFloat(item.result.phone_score))
      const toneScores = validItems.map(item => parseFloat(item.result.tone_score))
      
      overallScore.value = Math.round(totalScores.reduce((a, b) => a + b, 0) / totalScores.length)
      detailedScores.value = {
        fluency: Math.round(fluencyScores.reduce((a, b) => a + b, 0) / fluencyScores.length),
        initialsFinals: Math.round(phoneScores.reduce((a, b) => a + b, 0) / phoneScores.length),
        tones: Math.round(toneScores.reduce((a, b) => a + b, 0) / toneScores.length)
      }
      
      // 生成分析详情
      analysisDetails.value = generateAnalysisTips(validItems)
    }
    
    // 根据评测结果生成提示
    const generateAnalysisTips = (items) => {
      const tips = []
      
      // 分析声调准确度
      const toneScores = items.map(item => parseFloat(item.result.tone_score))
      const toneAvg = toneScores.reduce((a, b) => a + b, 0) / toneScores.length
      
      if (toneAvg >= 85) {
        tips.push({
          icon: 'fas fa-check-circle',
          color: '#4CAF50',
          text: '您的声调发音非常准确，继续保持！'
        })
      } else if (toneAvg >= 70) {
        tips.push({
          icon: 'fas fa-info-circle',
          color: '#2196F3',
          text: '声调发音基本准确，建议多练习第三声和轻声'
        })
      } else {
        tips.push({
          icon: 'fas fa-exclamation-triangle',
          color: '#FFC107',
          text: '声调发音需要加强，特别是第二声和第四声的区分'
        })
      }
      
      // 分析声母/韵母
      const phoneScores = items.map(item => parseFloat(item.result.phone_score))
      const phoneAvg = phoneScores.reduce((a, b) => a + b, 0) / phoneScores.length
      
      if (phoneAvg >= 85) {
        tips.push({
          icon: 'fas fa-check-circle',
          color: '#4CAF50',
          text: '声母和韵母发音清晰准确，非常好！'
        })
      } else if (phoneAvg >= 70) {
        tips.push({
          icon: 'fas fa-info-circle',
          color: '#2196F3',
          text: '部分声母发音需要加强，特别是平舌音和翘舌音'
        })
      } else {
        tips.push({
          icon: 'fas fa-exclamation-triangle',
          color: '#FFC107',
          text: '声母和韵母发音需要系统练习，注意区分相似音'
        })
      }
      
      // 分析流畅度
      const fluencyScores = items.map(item => parseFloat(item.result.fluency_score))
      const fluencyAvg = fluencyScores.reduce((a, b) => a + b, 0) / fluencyScores.length
      
      if (fluencyAvg >= 85) {
        tips.push({
          icon: 'fas fa-check-circle',
          color: '#4CAF50',
          text: '表达非常流畅，语速适中，节奏感好'
        })
      } else if (fluencyAvg >= 70) {
        tips.push({
          icon: 'fas fa-info-circle',
          color: '#2196F3',
          text: '表达基本流畅，但部分词语之间连贯性可以加强'
        })
      } else {
        tips.push({
          icon: 'fas fa-exclamation-triangle',
          color: '#FFC107',
          text: '流畅度需要提高，注意减少停顿和重复词语'
        })
      }
      
      // 总体建议
      tips.push({
        icon: 'fas fa-lightbulb',
        color: '#9C27B0',
        text: '建议每天练习15分钟，重点关注单词发音细节'
      })
      
      return tips
    }

    // 辅助函数
    const getPercentage = (score) => {
      return `${Math.round(score)}%`
    }

    const resetTraining = () => {
      trainingStarted.value = false
      trainingItems.value = []
      hasResults.value = false
      overallScore.value = 0
      detailedScores.value = {
        tones: 0,
        initialsFinals: 0,
        fluency: 0
      }
      analysisDetails.value = []
      // 停止所有录音
      if (audioContext.value) {
        audioContext.value.close()
        audioContext.value = null
      }
      audioProcessors.value.forEach(processor => {
        if (processor) {
          processor.disconnect()
        }
      })
    }

    return {
      trainingStarted,
      trainingItems,
      isSubmitting,
      hasResults,
      overallScore,
      detailedScores,
      analysisDetails,
      allRecorded,
      hasEvaluating,
      startTraining,
      toggleRecording,
      formatTime,
      submitEvaluations,
      resetTraining,
      getPercentage
    }
  }
}
</script>

<style scoped>
/* 添加拼音显示的样式 */
.pinyin-hint {
  font-size: 0.9rem;
  color: #7f8c8d;
  margin-top: 8px;
  font-style: italic;
}

/* 句子评测结果样式 */
.sentence-result {
  margin-top: 15px;
  padding: 15px;
  background-color: #f8f9fa;
  border-radius: 8px;
  border: 1px solid #e9ecef;
}

.result-summary {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-bottom: 15px;
}

.result-item {
  display: flex;
  justify-content: space-between;
  padding: 8px;
  background-color: white;
  border-radius: 6px;
}

.score-value {
  font-weight: bold;
  color: #3498db;
}

/* 评测状态指示器 */
.evaluating-indicator {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #3498db;
  font-weight: 500;
}

.result-indicator {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #4CAF50;
  font-weight: 500;
}

/* 其余样式保持不变 */
.speech-training-container {
  width: 100%;
  max-width: 1200px;
  background: white;
  border-radius: 20px;
  box-shadow: 0 15px 50px rgba(0, 0, 0, 0.3);
  overflow: hidden;
  margin: 20px auto;
}
.training-header {
  background: linear-gradient(135deg, #0f2027 0%, #203a43 50%, #2c5364 100%);
  color: white;
  padding: 25px 40px;
  text-align: center;
  position: relative;
}
.header-content {
  max-width: 800px;
  margin: 0 auto;
}
h1 {
  font-size: 2.8rem;
  margin-bottom: 15px;
  font-weight: 700;
  letter-spacing: 1px;
}
.subtitle {
  font-size: 1.2rem;
  opacity: 0.85;
  max-width: 700px;
  margin: 0 auto 20px;
  line-height: 1.6;
}
.main-content {
  display: flex;
  min-height: 600px;
}
.training-section {
  flex: 3;
  padding: 30px;
  background: #f9fbfd;
}
.results-section {
  flex: 2;
  padding: 30px;
  background: #f0f7ff;
  border-left: 1px solid #e1e8ed;
  overflow-y: auto;
  max-height: 600px;
}
.section-title {
  font-size: 1.8rem;
  margin-bottom: 25px;
  color: #2c3e50;
  display: flex;
  align-items: center;
  gap: 12px;
}
.section-title i {
  background: linear-gradient(135deg, #3498db, #2c3e50);
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}
.start-container {
  text-align: center;
  padding: 50px 20px;
  background: white;
  border-radius: 15px;
  box-shadow: 0 5px 25px rgba(0, 0, 0, 0.08);
  margin-top: 20px;
}
.start-btn {
  background: linear-gradient(135deg, #00b09b, #96c93d);
  color: white;
  border: none;
  padding: 20px 50px;
  font-size: 1.5rem;
  font-weight: 600;
  border-radius: 50px;
  cursor: pointer;
  transition: all 0.3s ease;
  box-shadow: 0 10px 25px rgba(0, 176, 155, 0.4);
  display: inline-flex;
  align-items: center;
  gap: 15px;
}
.start-btn:hover {
  transform: translateY(-5px);
  box-shadow: 0 15px 30px rgba(0, 176, 155, 0.5);
}
.start-btn:active {
  transform: translateY(-2px);
}
.start-btn i {
  font-size: 1.8rem;
}
.start-hint {
  margin-top: 15px;
  color: #7f8c8d;
  font-size: 1rem;
}
.training-items {
  display: flex;
  flex-direction: column;
  gap: 25px;
  margin-top: 20px;
}
.training-item {
  background: white;
  border-radius: 15px;
  padding: 25px;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
  border: 1px solid #eaeaea;
  transition: all 0.3s ease;
}
.training-item:hover {
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
  transform: translateY(-3px);
}
.item-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding-bottom: 15px;
  border-bottom: 1px dashed #e1e8ed;
}
.item-number {
  background: linear-gradient(135deg, #3498db, #2c3e50);
  color: white;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 1.1rem;
}
.item-content {
  font-size: 1.2rem;
  line-height: 1.7;
  margin-bottom: 25px;
  color: #2c3e50;
  background: #f8fafc;
  padding: 20px;
  border-radius: 10px;
  border-left: 4px solid #3498db;
}
.recording-controls {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.recording-btn {
  background: linear-gradient(135deg, #ff416c, #ff4b2b);
  color: white;
  border: none;
  padding: 12px 30px;
  font-size: 1.1rem;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  gap: 10px;
  box-shadow: 0 5px 15px rgba(255, 65, 108, 0.3);
}
.recording-btn:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 20px rgba(255, 65, 108, 0.4);
}
.recording-btn.recording {
  background: linear-gradient(135deg, #2c3e50, #1e3c72);
}
.recording-btn i {
  font-size: 1.3rem;
}
.recording-btn:disabled {
  background: #cccccc;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}
.recording-indicator {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #e74c3c;
  font-weight: 500;
}
.pulse {
  width: 15px;
  height: 15px;
  background: #e74c3c;
  border-radius: 50%;
  animation: pulse 1.5s infinite;
}
@keyframes pulse {
  0% { transform: scale(0.9); opacity: 0.7; }
  50% { transform: scale(1.2); opacity: 1; }
  100% { transform: scale(0.9); opacity: 0.7; }
}
.timer {
  font-size: 1.1rem;
  font-weight: 600;
  color: #2c3e50;
}
.audio-preview {
  flex: 1;
  margin-left: 20px;
}
audio {
  width: 100%;
  max-width: 250px;
}
.submit-section {
  margin-top: 40px;
  text-align: center;
}
.submit-btn {
  background: linear-gradient(135deg, #3498db, #2c3e50);
  color: white;
  border: none;
  padding: 16px 45px;
  font-size: 1.3rem;
  font-weight: 600;
  border-radius: 50px;
  cursor: pointer;
  transition: all 0.3s ease;
  box-shadow: 0 10px 25px rgba(52, 152, 219, 0.4);
  display: inline-flex;
  align-items: center;
  gap: 15px;
}
.submit-btn:hover:not(:disabled) {
  transform: translateY(-5px);
  box-shadow: 0 15px 30px rgba(52, 152, 219, 0.5);
}
.submit-btn:disabled {
  background: #cccccc;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}
.empty-results {
  text-align: center;
  padding: 60px 20px;
  color: #7f8c8d;
}
.empty-results i {
  font-size: 3rem;
  margin-bottom: 20px;
  color: #bdc3c7;
}
.empty-results p {
  font-size: 1.1rem;
  margin-top: 15px;
}
.results-container {
  padding: 10px;
}
.overall-score {
  margin-bottom: 30px;
}
.score-card {
  background: white;
  border-radius: 12px;
  padding: 25px;
  text-align: center;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}
.score-label {
  font-size: 1.1rem;
  color: #7f8c8d;
  margin-bottom: 5px;
}
.score-value {
  font-size: 3.5rem;
  font-weight: 700;
  color: #2c3e50;
  margin: 10px 0;
}
.score-percentage {
  font-size: 1.2rem;
  color: #3498db;
  font-weight: 600;
}
.score-progress {
  height: 10px;
  background: #ecf0f1;
  border-radius: 5px;
  margin-top: 20px;
  overflow: hidden;
}
.progress-bar {
  height: 100%;
  background: linear-gradient(90deg, #3498db, #2c3e50);
  border-radius: 5px;
  transition: width 0.5s ease;
}
.detailed-scores {
  margin: 30px 0;
}
.score-item {
  margin-bottom: 20px;
}
.score-info {
  display: flex;
  justify-content: space-between;
  margin-bottom: 8px;
}
.detailed-analysis {
  margin-top: 40px;
}
.detailed-analysis h3 {
  font-size: 1.3rem;
  margin-bottom: 20px;
  color: #2c3e50;
  display: flex;
  align-items: center;
  gap: 10px;
}
.analysis-item {
  background: white;
  border-radius: 10px;
  padding: 15px 20px;
  margin-bottom: 15px;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05);
}
.analysis-content {
  display: flex;
  align-items: flex-start;
  gap: 15px;
}
.analysis-content i {
  font-size: 1.5rem;
  margin-top: 3px;
}
.analysis-content p {
  flex: 1;
  line-height: 1.6;
}
.retry-section {
  margin-top: 40px;
  text-align: center;
}
.retry-btn {
  background: white;
  color: #3498db;
  border: 2px solid #3498db;
  padding: 12px 30px;
  font-size: 1.1rem;
  border-radius: 30px;
  cursor: pointer;
  transition: all 0.3s ease;
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.retry-btn:hover {
  background: #f0f7ff;
  transform: translateY(-3px);
}
@media (max-width: 768px) {
  .main-content {
    flex-direction: column;
  }
  .results-section {
    border-left: none;
    border-top: 1px solid #e1e8ed;
  }
  h1 {
    font-size: 2rem;
  }
  .start-btn, .submit-btn {
    padding: 15px 30px;
    font-size: 1.2rem;
  }
  .training-item {
    padding: 20px;
  }
  .recording-controls {
    flex-direction: column;
    gap: 15px;
  }
  .audio-preview {
    margin-left: 0;
    width: 100%;
  }
  .result-summary {
    grid-template-columns: 1fr;
  }
}
</style>